package com.cloud.async.business.context.support;

import com.cloud.async.business.body.FutureResult;
import com.cloud.async.business.context.AbstractAsyncContext;
import com.cloud.async.business.context.data.SingleDataSource;
import com.cloud.async.error.ErrorHandler;
import com.cloud.async.error.impl.DefaultErrorHandler;
import com.cloud.async.monitor.ResultHandlerMonitor;
import com.cloud.async.monitor.impl.DefaultResultHandlerMonitor;
import com.cloud.async.result.core.handler.StandardAsyncResultHandler;
import com.cloud.async.retry.DefaultRetryPolicy;
import com.cloud.async.retry.RetryPolicy;
import com.cloud.async.util.ex.AsyncException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

/**
 * @author chengrui
 * @title: ApplicationAsyncContext
 * @projectName webCloudAsync
 * @description: 完整子类，继承体系中最底层的实现
 * @date 2021/9/23 23:58
 */

public class StandardAsyncContext extends AbstractAsyncContext {

    /**
     * logger
     */
    private final Log logger = LogFactory.getLog(getClass());

    /**
     * 数据源
     */
    private ConcurrentHashMap<String, FutureResult> futureResultTaskSource;

    /**
     * 初始化本地存储Map
     *
     * @param dataCapacity
     */
    private void initializeDataSource(Integer dataCapacity) {
        this.futureResultTaskSource = SingleDataSource.INSTANCE.getSingleDataSource(dataCapacity);
    }

    @Override
    protected void releaseTask(String taskId) {
        this.futureResultTaskSource.remove(taskId);
    }

    @Override
    protected FutureResult getTaskResult(String taskId) {
        return this.futureResultTaskSource.get(taskId);
    }

    @Override
    protected boolean isTaskActive(String taskId) {
        return this.futureResultTaskSource.containsKey(taskId);
    }

    @Override
    protected void registerTask(String taskId, FutureResult value) {
        try {
            // 使用 compute() 原子性检查并插入
            FutureResult existing = futureResultTaskSource.compute(taskId, (key, oldValue) -> {
                if (oldValue != null) {
                    throw new IllegalStateException("TaskId already exists: " + taskId);
                }
                return value;
            });
        } catch (IllegalStateException e) {
            logger.error("Failed to save task: " + e.getMessage());
            throw e;
        } catch (Exception e) {
            logger.error("Unexpected error while saving futureResultTaskSource: " + e);
            throw e;
        }
    }


    /**
     *
     * @param builder
     */
    public StandardAsyncContext(Builder builder) {
        initialize(builder.executor, builder.globalTimeout,
                builder.resultHandler,
                builder.errorHandlerCls, builder.resultHandlerMonitorCls, builder.retryPolicyCls,
                builder.errorHandler, builder.resultHandlerMonitor, builder.retryPolicy);

        initializeDataSource(builder.dataCapacity);
    }

    public static class Builder {
        /**
         * 线程池
         */
        private Executor executor;
        private Long globalTimeout = 1000L;
        private Integer dataCapacity = 1024;


        /**
         * 结果处理
         */
        private Class<?> resultHandler = StandardAsyncResultHandler.class;


        /**
         * 处理异步任务执行过程中的异常
         * 用于监控异步任务的生命周期
         * 重试机制 默认
         * 优先级最高 Class优先级高于Object
         */
        private ErrorHandler errorHandler = new DefaultErrorHandler();
        private ResultHandlerMonitor resultHandlerMonitor = new DefaultResultHandlerMonitor();
        private RetryPolicy retryPolicy = new DefaultRetryPolicy();

        /**
         * 处理异步任务执行过程中的异常
         * 用于监控异步任务的生命周期
         * 重试机制 默认
         * 优先级最高 Class优先级高于Object
         */
        private Class<? extends ErrorHandler> errorHandlerCls = DefaultErrorHandler.class;
        private Class<? extends ResultHandlerMonitor> resultHandlerMonitorCls = DefaultResultHandlerMonitor.class;
        private Class<? extends RetryPolicy> retryPolicyCls = DefaultRetryPolicy.class;

        // 必填参数校验
        public Builder executor(Executor executor) {
            this.executor = executor;
            return this;
        }
        public Builder globalTimeout(long globalTimeout) {
            this.globalTimeout = globalTimeout;
            return this;
        }
        public Builder dataCapacity(Integer dataCapacity) {
            this.dataCapacity = dataCapacity;
            return this;
        }

        public Builder resultHandler(Class<?> resultHandler) {
            this.resultHandler = resultHandler;
            return this;
        }


        public Builder lifeHandler(ErrorHandler errorHandler, ResultHandlerMonitor monitor) {
            this.errorHandlerCls = null;
            this.resultHandlerMonitorCls = null;

            this.errorHandler = errorHandler;
            this.resultHandlerMonitor = monitor;
            return this;
        }
        public Builder lifeHandler(Class<? extends ErrorHandler> errorHandlerCls,Class<? extends ResultHandlerMonitor> resultHandlerMonitorCls ) {
            this.errorHandler = null;
            this.resultHandlerMonitor = null;

            this.errorHandlerCls = errorHandlerCls;
            this.resultHandlerMonitorCls = resultHandlerMonitorCls;
            return this;
        }


        /**
         * 重试类 方法实现
         * @param retryPolicyCls
         * @return
         */
        public Builder retryPolicy(Class<? extends RetryPolicy> retryPolicyCls) {
            this.retryPolicy = null;
            this.retryPolicyCls = retryPolicyCls;
            return this;
        }
        public Builder retryPolicy(RetryPolicy retryPolicy) {
            this.retryPolicyCls = null;
            this.retryPolicy = retryPolicy;
            return this;
        }

        // 构建方法
        public StandardAsyncContext build() {
            if (executor == null) {
                throw new AsyncException("Executor is required");
            }
            if (globalTimeout == null || globalTimeout <= 0 || globalTimeout > 1000 * 60) {
                throw new AsyncException(
                        "Invalid globalTimeout: " + globalTimeout + ". " +
                                "Expected: 0 < globalTimeout ≤ 60000 (1 minute), but got: " + globalTimeout
                );
            }
            if (dataCapacity == null) {
                throw new AsyncException("dataCapacity is required");
            }
            return new StandardAsyncContext(this);
        }
    }

}
